import re
from rest_framework import serializers
from rest_framework_simplejwt.tokens import AccessToken
from django.core.cache import cache
from django.conf import settings
from rest_framework.exceptions import ValidationError
from .models import User


class LoginSerializerMixin:
    def _get_user(self, attrs):
        raise Exception('在%s中,方法【_get_user】必须被重写' % self.__class__.__name__)

    def _get_token(self, user):
        # 使用simple-jwt签发token
        token = AccessToken.for_user(user)
        return str(token)

    def _pre_data(self, token, user):
        self.context['token'] = token
        self.instance = user  # 当前用户，放到instance中了

    def validate(self, attrs):
        # 1 取出用户名(手机号，邮箱)和密码
        user = self._get_user(attrs)
        # 2 如果存在：签发token，返回
        token = self._get_token(user)
        # 3 把token,用户名和icon放入context
        self._pre_data(token, user)
        return attrs


class MulLoginSerializer(LoginSerializerMixin, serializers.ModelSerializer):
    # 需要重写username字段，去除模型表中自带的unique限制
    username = serializers.CharField()

    class Meta:
        model = User
        fields = ['username', 'password', 'icon']
        extra_kwargs = {
            'password': {'write_only': True},
        }

    def _get_user(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        # 多方式登录
        if re.match(r'^1[3-9][0-9]{9}$', username):
            # 手机号
            user = User.objects.filter(mobile=username).first()
        elif re.match('^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$', username):
            # 邮箱
            user = User.objects.filter(email=username).first()
        else:
            # 用户名
            user = User.objects.filter(username=username).first()

        if user and user.check_password(password):
            # 校验密码
            return user
        else:
            raise ValidationError({'username': '用户名或密码错误'})


class SmsLoginSerializer(LoginSerializerMixin, serializers.ModelSerializer):
    mobile = serializers.CharField()
    code = serializers.CharField(write_only=True)

    class Meta:
        model = User
        fields = ['username', 'icon', 'mobile', 'code']
        extra_kwargs = {
            'username': {'read_only': True},
            'icon': {'read_only': True},
        }

    def _get_user(self, attrs):
        # 取出手机号
        mobile = attrs.get('mobile')
        # 取出验证码
        code = attrs.get('code')
        # 校验验证码
        old_code = cache.get(f'cache_code_{mobile}')
        # 非生产环境可以使用万能验证码
        assert old_code == code or (settings.DEBUG and code == '8888'), ValueError('验证码错误')
        user = User.objects.filter(mobile=mobile).first()
        assert user, ValueError('该手机号用户没注册')
        return user


class RegisterSerializer(serializers.ModelSerializer):
    code = serializers.CharField()

    class Meta:
        model = User
        fields = ['mobile', 'password', 'code']
        extra_kwargs = {
            'mobile': {'error_messages': {'invalid': '当前手机号已注册'}}
        }

    def validate(self, attrs):
        # 弹出code，后续保存数据不需要使用
        code = attrs.pop('code')
        mobile = attrs.get('mobile')
        # 2 校验验证码
        old_code = cache.get(f'cache_code_{mobile}')
        assert old_code == code or (settings.DEBUG and code == '8888'), ValidationError('验证码错误')
        # 将用户名放入validated_data中
        attrs['username'] = mobile
        # 3 返回
        return attrs

    def create(self, validated_data):
        # 创建用户
        user = User.objects.create_user(**validated_data)
        return user
